import 'dart:async';

import 'package:bot_toast/bot_toast.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:xm_flutter_ui/will_pop_interceptor.dart';
import 'package:xm_flutter_ui/xm_flutter_ui.dart';

import '../xm_ui_common.dart';
import 'alert_action.dart';

export 'alert_action.dart';

typedef CloseAlertDialogBlock = void Function({bool? animated});
typedef ShouldCloseAlertDialogCallback = Future<bool> Function(
    CloseAlertDialogBlock closeBlock);
typedef FLAlertDialogWidgetBuilder = Widget Function(
    BuildContext context, CloseAlertDialogBlock closeBlock);

class AlertDialogStyle {
  Map<int, AlertActionStyle> _actionsStyle = Map();

  AlertActionStyle getActionStyle(int actionTag) {
    AlertActionStyle? actionStyle = _actionsStyle[actionTag];
    if (actionStyle != null) {
      return actionStyle;
    }

    if (actionTag == AlertAction.destructive) {
      actionStyle = AlertActionStyle.destructiveStyle;
    } else if (actionTag == AlertAction.ok) {
      actionStyle = AlertActionStyle.okStyle;
    } else if (actionTag == AlertAction.cancel) {
      actionStyle = AlertActionStyle.cancelStyle;
    }

    return (actionStyle ?? AlertActionStyle.defaultStyle);
  }

  void setActionStyle(int actionTag, AlertActionStyle actionStyle) {
    _actionsStyle[actionTag] = actionStyle;
  }

  static AlertDialogStyle get defaultStyle {
    AlertDialogStyle style = AlertDialogStyle();
    return style;
  }
}

class _DialogActionButton extends StatelessWidget {
  const _DialogActionButton({
    Key? key,
    required this.title,
    this.style,
    this.onPressed,
  }) : super(key: key);

  final String title;
  final TextStyle? style;
  final VoidCallback? onPressed;

  @override
  Widget build(BuildContext context) {
    return TextButton(
      onPressed: onPressed,
      child: Text(
        title,
        style: this.style,
      ),
    );
  }
}

/// Flutter Dialog
class FLAlertDialog {
  static Future<AlertAction> showAlertDialog({
    Widget? title,
    Widget? content,
    AlertDialogStyle? dialogStyle,
    bool enableKeyboardSafeArea = false,
    List<AlertAction>? actions,
    TapAlertActionCallback? tapAlertActionCallback,
    ShouldCloseAlertDialogCallback? closeCallback,
  }) {
    Completer<AlertAction> completer = Completer<AlertAction>();

    BotToast.showEnhancedWidget(
      enableKeyboardSafeArea: enableKeyboardSafeArea,
      toastBuilder: (CancelFunc cancelFunc) {
        closeCallback?.call(({bool? animated}) {
          cancelFunc();
        });

        dialogStyle = dialogStyle ?? AlertDialogStyle.defaultStyle;

        List<Widget>? actionWidgets;
        if (actions != null) {
          actionWidgets = actions.map((e) {
            return _DialogActionButton(
              title: e.title,
              style: dialogStyle!.getActionStyle(e.tag).textStyle,
              onPressed: () {
                if (tapAlertActionCallback != null) {
                  if (tapAlertActionCallback(e) == false) {
                    return;
                  }
                }
                cancelFunc();
                Future.microtask(() {
                  completer.complete(e);
                });
              },
            );
          }).toList(growable: false);
        }

        return Material(
          color: Colors.transparent,
          child: Overlay(
            initialEntries: [
              OverlayEntry(builder: (_) {
                return AlertDialog(
                  title: title,
                  content: content,
                  actions: actionWidgets,
                );
              }),
            ],
          ),
        );
      },
    );

    return completer.future;
  }

  static Future<AlertAction> showMessageDialog({
    AlertDialogStyle? dialogStyle,
    String? title,
    String? message,
    TextSpan? messageTextSpan,
    bool enableKeyboardSafeArea = false,
    List<AlertAction>? actions,
    List<int>? actionTags,
    TapAlertActionCallback? tapAlertActionCallback,
    ShouldCloseAlertDialogCallback? closeCallback,
  }) {
    if (actions == null) {
      if (actionTags != null) {
        actions = actionTags.map((e) {
          return AlertAction(tag: e);
        }).toList(growable: false);
      }
    }

    if (actions == null) {
      actions = [
        AlertAction(tag: AlertAction.ok),
      ];
    }

    Widget content = messageTextSpan != null
        ? SelectableText.rich(messageTextSpan)
        : SelectableText(message!);

    dialogStyle ??= AlertDialogStyle.defaultStyle;
    return showAlertDialog(
      title: title != null ? Text(title) : null,
      content: content,
      dialogStyle: dialogStyle,
      actions: actions,
      enableKeyboardSafeArea: enableKeyboardSafeArea,
      tapAlertActionCallback: tapAlertActionCallback,
      closeCallback: closeCallback,
    );
  }

  static void showBottomSheet({
    OverlayState? overlayState,
    BuildContext? context,
    required FLAlertDialogWidgetBuilder builder,
    ShouldCloseAlertDialogCallback? shouldCloseCallback,
    WillPopInterceptor? popInterceptor,
  }) {
    if (overlayState == null) {
      showModalBottomSheet(
          context: context!,
          backgroundColor: Colors.transparent,
          isDismissible: true,
          builder: (context) {
            final widget = _ActionSheetContainer(
              customAnimation: false,
              builder: builder,
              popInterceptor: popInterceptor,
              closeBlock: ({bool? animated}) {
                Navigator.of(context).pop();
              },
              shouldCloseAlertDialogCallback: shouldCloseCallback,
            );

            return WillPopScope(
              child: widget,
              onWillPop: () async {
                if (widget._triggerCloseBlock != null) {
                  return await widget._triggerCloseBlock!();
                }
                return true;
              },
            );
          });
    } else {
      late OverlayEntry overlayEntry;
      overlayEntry = OverlayEntry(builder: (context) {
        final widget = _ActionSheetContainer(
          customAnimation: true,
          popInterceptor: popInterceptor,
          builder: builder,
          closeBlock: ({bool? animated}) {
            overlayEntry.remove();
          },
          shouldCloseAlertDialogCallback: shouldCloseCallback,
        );

        return WillPopScope(
          child: widget,
          onWillPop: () async {
            if (widget._triggerCloseBlock != null) {
              return await widget._triggerCloseBlock!();
            }
            return true;
          },
        );
      });

      overlayState.insert(overlayEntry);
    }
  }
}

// ignore: must_be_immutable
class _ActionSheetContainer extends StatefulWidget {
  _ActionSheetContainer({
    Key? key,
    required this.builder,
    required this.closeBlock,
    this.customAnimation = false,
    this.shouldCloseAlertDialogCallback,
    this.popInterceptor,
  }) : super(key: key);

  final bool customAnimation;
  final FLAlertDialogWidgetBuilder builder;
  final CloseAlertDialogBlock closeBlock;
  final ShouldCloseAlertDialogCallback? shouldCloseAlertDialogCallback;
  final WillPopInterceptor? popInterceptor;
  WillPopCallback? _triggerCloseBlock;

  @override
  __ActionSheetContainerState createState() => __ActionSheetContainerState();
}

class __ActionSheetContainerState extends State<_ActionSheetContainer>
    with SingleTickerProviderStateMixin {
  AnimationController? animationController;
  Animation<Offset>? _offsetTween;

  Animation<double>? _opacityTween;

  late CloseAlertDialogBlock _closeAlertDialogBlock;

  var _popInterceptorBlock;

  @override
  void initState() {
    widget._triggerCloseBlock = () async {
      _tapBackgroundView();
      return false;
    };

    _closeAlertDialogBlock = ({animated}) {
      animated ??= true;
      _close(animated);
    };

    if (widget.customAnimation) {
      animationController = AnimationController(
          duration: Duration(milliseconds: 200), vsync: this);
      _offsetTween = Tween(begin: Offset(0.0, 1.0), end: Offset.zero)
          .animate(animationController!);
      _opacityTween = Tween(begin: 0.0, end: 1.0).animate(animationController!);
      animationController!.forward();
    }

    if (widget.popInterceptor != null) {
      _popInterceptorBlock = () async {
        if (mounted != true) {
          return WillPopInterceptorResult(pop: true, autoRemove: true);
        }
        bool close = await _tapBackgroundView();
        return WillPopInterceptorResult(pop: false, autoRemove: close);
      };
      widget.popInterceptor!.addInterceptor(_popInterceptorBlock);
    }

    super.initState();
  }

  @override
  void dispose() {
    if (widget.customAnimation) {
      animationController?.stop();
      animationController?.dispose();
    }
    if (_popInterceptorBlock != null) {
      widget.popInterceptor!.removeInterceptor(_popInterceptorBlock);
    }

    super.dispose();
  }

  void _close(bool animated) async {
    if (widget.customAnimation && animated) {
      await animationController?.reverse();
    }
    widget.closeBlock();
  }

  Future<bool> _tapBackgroundView() async {
    if (widget.shouldCloseAlertDialogCallback != null &&
        (await widget
                .shouldCloseAlertDialogCallback!(_closeAlertDialogBlock)) ==
            false) {
      return false;
    }
    _close(true);
    return true;
  }

  Widget _buildContent(BuildContext context) {
    return ClipRRect(
      borderRadius: BorderRadius.vertical(top: Radius.circular(8.0)),
      child: widget.builder(context, _closeAlertDialogBlock),
    );
  }

  @override
  Widget build(BuildContext context) {
    if (widget.customAnimation == false) {
      return _buildContent(context);
    }

    return Material(
      color: Colors.transparent,
      child: Overlay(
        initialEntries: [
          OverlayEntry(builder: (context) {
            return Builder(
              builder: (context) {
                return Stack(
                  children: [
                    Positioned.fill(
                      child: FadeTransition(
                        opacity: _opacityTween!,
                        child: GestureDetector(
                          child: Container(
                            color: XMFlutterColor.fromWhite(0.2, alpha: 0.6),
                          ),
                          onTap: _tapBackgroundView,
                        ),
                      ),
                    ),
                    Positioned(
                      left: 0.0,
                      right: 0.0,
                      bottom: 0.0,
                      child: SlideTransition(
                        position: _offsetTween!,
                        child: _buildContent(context),
                      ),
                    ),
                  ],
                );
              },
            );
          })
        ],
      ),
    );
  }
}
